<template>
  <el-popover ref="popperVue" popper-class="filter-select__popper" trigger="click" :disabled="disabled">
    <template #reference>
      <slot :valueStr="valueStr"></slot>
    </template>
    <div class="popper-content" :class="filterable ? 'has-filter' : ''">
      <div class="search" v-if="filterable">
        <el-input v-model="search" :prefix-icon="Search" clearable placeholder="输入关键词搜索"></el-input>
      </div>

      <div class="seleced-tips" v-if="multiple">
        已选{{ modelValue && modelValue.length || 0 }}项
        <span class="c-primary cursor-pointer" v-show="modelValue && modelValue.length" @click="onClear">清除已选</span>
      </div>

      <div class="option-list" v-loading="loading">
        <div class="option" v-for="item in renderOption" :key="item[optionProp.value]"
          :class="isActive(item[optionProp.value]) ? 'active' : ''" @click="onSelect(item[optionProp.value])">
          <slot name="prefix" :item="item"></slot> {{ item[optionProp.label] }}
        </div>
      </div>
    </div>
  </el-popover>
</template>

<script setup>
import { Search } from '@element-plus/icons-vue';
import { computed, nextTick, watch, ref, toRefs, watchEffect } from 'vue';
const emit = defineEmits(['update:modelValue', 'change'])
const props = defineProps({
  modelValue: [String, Number, Boolean, Object, Array],
  label: String,
  options: {
    type: Array,
    default: () => ([])
  },
  optionProp: {
    type: Object,
    default: () => ({ label: 'label', value: 'value' })
  },
  multiple: Boolean,
  filterable: Boolean,
  remote: Boolean,
  remoteMethod: Function,
  disabled: Boolean,
  loading: Boolean,
});

const popperVue = ref();

const { modelValue, options, optionProp, multiple, filterable, remote } = toRefs(props);

const valueStr = ref('');
function setValueStr() {
  if (modelValue.value && options.value?.length > 0) {
    const { label: labelKey, value: valueKey } = optionProp.value;
    if (multiple.value) {
      valueStr.value = modelValue.value.map(val => {
        const item = options.value.find(v => val === v[valueKey]);
        return item?.[labelKey] || ''
      }).join('，')
    } else {
      const item = options.value.find(v => modelValue.value === v[valueKey]);
      valueStr.value = item?.[labelKey];
    }
  } else {
    valueStr.value = '';
  }
}

watch(modelValue, (val) => {
  setValueStr();
  if (multiple.value && !Array.isArray(val)) {
    console.warn('multiple模式下，modelValue的类型应该是数组，但是传入的是', multiple.value)
  }
}, { deep: true, immediate: true })

const onSelect = (val) => {
  let res = val;
  if (multiple.value) {
    modelValue.value.push(val);
    res = modelValue.value;
  } else {
    popperVue.value.hide();
  }
  emit('update:modelValue', res);
  emit('change', res);
}
const onClear = () => {
  let res = null;
  if (multiple.value) {
    res = []
  }
  popperVue.value.hide();
  emit('update:modelValue', res);
  emit('change', res);
}

const isActive = (val) => {
  if (multiple.value) {
    return modelValue.value.includes(val);
  } else {
    return modelValue.value === val;
  }
}

const search = ref();
const filterOption = ref([...options.value]);
const filterMethod = (kw) => {
  if (!kw) {
    filterOption.value = [...options.value];
    return;
  }
  const labelKey = optionProp.value.label;
  filterOption.value = options.value.filter(v => v[labelKey].includes(kw))
}

watchEffect(() => {
  let kw = search.value;
  if (remote.value) {
    nextTick(() => {
      props.remoteMethod && props.remoteMethod(kw);
    })
  } else {
    filterMethod(kw);
  }
});

// 实际渲染的选项
const renderOption = computed(() => {
  if (filterable.value && !remote.value) {
    return filterOption.value;
  } else {
    return options.value;
  }
})
</script>

<style lang="scss" scoped>
.filter-item {
  display: inline-flex;
  align-items: center;
  font-size: 14px;
  height: 28px;
  line-height: 28px;
  padding: 0 8px;
  color: rgba(32, 45, 64, 0.6);
  cursor: pointer;
  background-color: #F5F7FA;
  border-radius: 3px;

  &.is-disabled {
    cursor: not-allowed;
  }

  .label {
    margin-right: 8px;
  }

  .value {
    color: rgba(32, 45, 64, 1);
    max-width: 230px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .icon {
    font-size: 12px;
    color: #BABEC4;
  }

  &+.filter-item {
    margin-left: 20px;
  }
}

.popper-content {
  display: inline-block;
  width: 100%;
  position: relative;

  &.has-filter {
    padding-top: 42px;
  }

  .search {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    padding: 4px 0;
    border-bottom: 1px solid #f3f3f3;

    :deep(.el-input__wrapper) {
      box-shadow: none;
      font-size: 12px;
    }
  }

  .seleced-tips {
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: 34px;
    border-bottom: 1px solid #f3f3f3;
    font-size: 13px;
    padding: 0 12px;
    color: #b9bdc3;
  }

  .option-list {
    display: inline-block;
    width: 100%;
    max-height: 60vh;
    overflow-y: auto;

    .option {
      display: flex;
      align-items: center;
      height: 35px;
      padding: 0 12px;
      font-size: 12px;
      white-space: nowrap;
      cursor: pointer;

      &.active,
      &:hover {
        background-color: #f3f3f3;
      }
    }
  }
}
</style>
<style>
.el-popper.filter-select__popper {
  padding: 0;
  width: auto !important;
}
</style>